#include "gb28181_utils.h"
#include "utils_log.h"
#include <sstream>
#include <iomanip>
#include <random>
#include <chrono>
#include <cstring>

extern "C" {
#include <osipparser2/osip_md5.h>
}

namespace El {
namespace GB28181 {

std::string GB28181Utils::GenerateCallId()
{
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::uniform_int_distribution<> dis(0, 15);

    std::stringstream ss;
    for (int i = 0; i < 32; ++i) {
        ss << std::hex << dis(gen);
    }

    return ss.str();
}

std::string GB28181Utils::GenerateNonce()
{
    return GenerateCallId();
}

std::string GB28181Utils::CalculateResponse(const std::string &username,
                                          const std::string &realm,
                                          const std::string &password,
                                          const std::string &nonce,
                                          const std::string &method,
                                          const std::string &uri)
{
    std::string ha1 = username + ":" + realm + ":" + password;
    std::string ha2 = method + ":" + uri;
    
    osip_MD5_CTX md5_ctx;
    unsigned char hash[16];
    char hex_hash[33];

    // Calculate HA1
    osip_MD5Init(&md5_ctx);
    osip_MD5Update(&md5_ctx, (unsigned char *)ha1.c_str(), ha1.length());
    osip_MD5Final(hash, &md5_ctx);

    for (int i = 0; i < 16; ++i) {
        sprintf(hex_hash + i * 2, "%02x", hash[i]);
    }
    hex_hash[32] = '\0';
    std::string ha1_hex(hex_hash);

    // Calculate HA2
    osip_MD5Init(&md5_ctx);
    osip_MD5Update(&md5_ctx, (unsigned char *)ha2.c_str(), ha2.length());
    osip_MD5Final(hash, &md5_ctx);

    for (int i = 0; i < 16; ++i) {
        sprintf(hex_hash + i * 2, "%02x", hash[i]);
    }
    hex_hash[32] = '\0';
    std::string ha2_hex(hex_hash);

    // Calculate response
    std::string response_str = ha1_hex + ":" + nonce + ":" + ha2_hex;

    osip_MD5Init(&md5_ctx);
    osip_MD5Update(&md5_ctx, (unsigned char *)response_str.c_str(), response_str.length());
    osip_MD5Final(hash, &md5_ctx);

    for (int i = 0; i < 16; ++i) {
        sprintf(hex_hash + i * 2, "%02x", hash[i]);
    }
    hex_hash[32] = '\0';

    return std::string(hex_hash);
}

std::string GB28181Utils::UnquoteString(const char* str)
{
    if (!str) return "";
    std::string result(str);
    // Remove leading and trailing quotes if present
    if (result.length() >= 2 && result.front() == '"' && result.back() == '"') {
        return result.substr(1, result.length() - 2);
    }
    return result;
}

std::string GB28181Utils::GetTimestamp()
{
    auto now = std::chrono::system_clock::now();
    auto time_t_now = std::chrono::system_clock::to_time_t(now);
    std::tm tm_now;
    localtime_r(&time_t_now, &tm_now);
    
    std::stringstream ss;
    ss << std::put_time(&tm_now, "%Y-%m-%dT%H:%M:%S");
    return ss.str();
}

std::string GB28181Utils::GenerateSN()
{
    return GenerateCallId().substr(0, 8);
}

} // namespace GB28181
} // namespace El